/**
 *
 * © Bahadir Zeren 2011
 * bzeren@gmail.com
 * No warranties, express or implied, are made for this program.
 *
 */

package org.baatar.net.tcp;

import org.baatar.thread.ThreadManager;
import org.baatar.thread.ThreadStatus;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import org.apache.log4j.Logger;

/**
 * TCP service class which extends ThreadManager interface.
 * It uses blocking socket approach to accept incoming TCP request messages
 * and sends responses back after processing.
 * 
 * @author b_zeren
 */
public class TCPService extends ThreadManager {

    private IMessageProcessor messageProcessor = null;

    private ServerSocket servSocket = null;
    private String hostName = null;
    private int listenerPort = 0;
    private int backLog = 1000;
    private Logger logger = null;

    /**
     * Constructor of the TCPService.
     * 
     * @param messageProcessor the message processor which will be used to 
     * process incoming request messages.
     */
    public TCPService(IMessageProcessor messageProcessor) {
        this.messageProcessor = messageProcessor;
    }

    /**
     * Initializes TCPService object.
     * Creates ServerSocket, determines the host name and such parameters..
     * 
     * @returns boolean true if initialization is successful.
     */
    @Override
    protected boolean initializeManager() throws Exception {
        this.servSocket = new ServerSocket(listenerPort, backLog);
        this.listenerPort = servSocket.getLocalPort();
        this.hostName = InetAddress.getLocalHost().getHostName();
        //  Overwrite threadName
        this.threadName = this.threadName + "-" + hostName + ":" + listenerPort;
        return true;
    }

    /**
     * Finalizes TCPService object.
     * Closes ServerSocket..
     * 
     */
    @Override
    protected void finalizeManager() throws IOException {

        servSocket.close();
        servSocket = null;

    }

    /**
     * Main method which listens for incoming Requests and accepts.
     * It generates a TCPMessageProcessThread object for each Request and starts
     * the process.
     * 
     */
    @Override
    protected void goAhead() throws InterruptedException, IOException {
        if (servSocket != null)
            try {
                while (!processCancelled()) {
                    Socket clientSocket = null;
                    try {
                        clientSocket = servSocket.accept();
                    } catch (SocketException ex) {
                        logger.error(ex.getMessage());
                    }
                    (new TCPMessageProcessThread(messageProcessor, 
                                                    clientSocket,
                                                    logger)).start();
                }
            } finally {
                servSocket.close();
            }
    }

    /**
     * Runs necessary tasks when status of the TCP service object is changed.
     * 
     * @param oldThreadStatus previous value of the status of the TCP service 
     * object.
     * 
     * @param newThreadStatus new value of the status of the TCP service object.
     */
    @Override
    protected void statusChanged(ThreadStatus oldThreadStatus, ThreadStatus newThreadStatus) {
    }

    /**
     * Runs necessary tasks when status of the TCP service object is being 
     * changed. If it is being stopped it will close server socket object.
     * 
     * @param oldThreadStatus previous value of the status of the TCP service 
     * object.
     * 
     * @param newThreadStatus new value of the status of the TCP service object.
     */
    @Override
    protected void statusIsBeingChanged(ThreadStatus oldThreadStatus, ThreadStatus newThreadStatus) {
        try {
            if ((newThreadStatus == ThreadStatus.tsStopped)
                && (servSocket != null)) {
            	servSocket.close();
            }
        } catch (IOException ex) {
        }
    }

    /**
     * Host name of the TCP service object.
     * 
     * @return the hostName
     */
    public String getHostName() {
        return hostName;
    }

    /**
     * Port number which is in use for accepting connections.
     * 
     * @return the listenerPort
     */
    public int getListenerPort() {
        return listenerPort;
    }

    /**
     * Size of the backlog of the ServerSocket object.
     * 
     * @see ServerSocket
     * 
     * @return the backLog
     */
    public int getBackLog() {
        return backLog;
    }

    /**
     * Sets the listener port number of the ServerSocket object.
     * It will be valid when TCP service object is initialized.
     * 
     * @param listenerPort the port number which will be used to accept incoming
     * Request messages.
     * 
     * @see ServerSocket
     * 
     */
    public void setListenerPort(int listenerPort) {
        this.listenerPort = listenerPort;
    }

    /**
     * Sets the backLog property of the ServerSocket object.
     * It will be valid when TCP service object is initialized.
     * 
     * @param backLog ServerSocket property which indicates how many messages
     * will wait in the queue.
     * 
     * @see ServerSocket
     * 
     */
    public void setBackLog(int backLog) {
        this.backLog = backLog;
    }

    /**
     * @return the logger
     */
    public Logger getLogger() {
        return logger;
    }

    /**
     * @param logger the logger to set
     */
    public void setLogger(Logger logger) {
        this.logger = logger;
    }

}
